#include "Manager.h"
#include "common.h"
#include "Log.h"
#include "JsonAnalysis.h"

CManager::CManager(int nTerminalId, const char *pSaveFilePath, OnMessageCallback callback, void *pUser)
	: m_bExit(false)
	, m_bConnect(false)
	, m_nTerminalId(nTerminalId)
	, m_pCmd(NULL)
	, m_pMedia(NULL)
	, m_pWb(NULL)
	, m_pCallback(callback)
	, m_pUser(pUser)
	, m_pVideoEncoder(NULL)
	, m_pVideoDecoder(NULL)
	, m_pVideoCapture(NULL)
	, m_pVideoBuf(NULL)
	, m_nWidth(0)
	, m_nHeight(0)
	, m_bInitRender(false)
	, m_bSendVideoSignal(false)
	, m_pAudioMan(NULL)
	, m_bScreen(false)
	, m_bFirst(true)
{
	memset(m_szSvrIp, 0x00, MAX_IPADRESS_LEN);
	memset(m_szTermianlId, 0x00, 12);
	
	sprintf_s(m_szTermianlId, "%d", nTerminalId);

	m_strSavePath = pSaveFilePath;	

	m_pWb = new CWhiteBoardManager(this);

	m_pWb->InitWhiteBoard(m_strSavePath);	

	m_pVideoCapture = new CVideoCapture(this);	

	m_pAudioMan = CreateAuidoManager();	

	StartThread();
}

CManager::~CManager(void)
{
	Stop();

	DestoryAuidoManager(m_pAudioMan);
}

bool CManager::StartApp(const char *pSvrIp, unsigned short usPort)
{
	memcpy(m_szSvrIp, pSvrIp, MAX_IPADRESS_LEN);
	m_usSvrPort = usPort;

	if (!m_pCmd)
		m_pCmd = new CCmdChannel(this);

	if (!m_pMedia)
		m_pMedia = new CMediaChannel(this);	

	m_pCmd->Start();
	m_pMedia->Start();

	m_pAudioMan->StartAudioPlay();

	return true;
}

void CManager::Stop(void)
{
	m_bExit = true;

	WaitForStop();

	if (m_pCmd)
	{
		delete m_pCmd;
		m_pCmd = NULL;
	}

	if (m_pMedia)
	{
		delete m_pMedia;
		m_pMedia = NULL;
	}

	if (m_pWb)
	{
		delete m_pWb;
		m_pWb = NULL;
	}

	while (m_lstRecvData.size())
	{
		LPRecvDataInfo pRecvData = NULL;

		{
			CAutoLock autoLock(&m_lockRecvData);
			pRecvData = (LPRecvDataInfo)m_lstRecvData.front();
			m_lstRecvData.pop_front();
		}

		if (pRecvData)
		{
			if (pRecvData->pData)
			{
				delete [] pRecvData->pData;
				pRecvData->pData = NULL;
			}

			delete pRecvData;
			pRecvData = NULL;
		}
	}
}

bool CManager::SetPlayWindows(unsigned long ulLocalVideo, unsigned long ulRemoteVideo)
{	
	RECT rc;
	GetClientRect((HWND)ulRemoteVideo, &rc);

	m_nOutWidth = rc.right - rc.left;
	m_nOutHeigth = rc.bottom - rc.top;

	m_pVideoCapture->SetDisplayWindow(ulLocalVideo);

	m_ulRemoteVideo = ulRemoteVideo;

	return true;
}

char *CManager::GetSvrIp(void)
{
	return m_szSvrIp;
}
unsigned short CManager::GetSvrPort(void)
{
	return m_usSvrPort;
}

int	CManager::GetTerminalId(void)
{
	return m_nTerminalId;
}

string CManager::GetFileSavePath(void)
{
	return m_strSavePath;
}

uint32_t CManager::GetWindowHandle(void)
{
	return m_pWb->GetWindowHandle();
}

void CManager::ClearLocalWbData(void)
{
	return m_pWb->ClearLocalWbData();
}

void CManager::SetWbMode(bool bMode)
{
	m_pWb->SetLocalMode(bMode);
}

void CManager::EnableDataOperationRight(bool bEnable)
{
	m_pWb->EnableDataOperationRight(bEnable);
}

void CManager::EnadleSync(bool bEnable)
{
	m_pWb->EnadleSync(bEnable);
}

void CManager::PutRecvData(RecvDataInfo *pRecv)
{
	CAutoLock autoLock(&m_lockRecvData);
	m_lstRecvData.push_back(pRecv);
}

void CManager::PutScreenBroadcastData(RecvDataInfo *pRecv)
{
	if (pRecv->nCmd == AUDIO_DATA)
	{
		if (m_pAudioMan && pRecv->nMsgLen > 0)
		{
			m_pAudioMan->PlayAudio(pRecv->pData, pRecv->nMsgLen -1);
		}

		if (pRecv)
		{
			if (pRecv->pData)
			{
				delete [] pRecv->pData;
				pRecv->pData = NULL;
			}

			delete pRecv;
			pRecv = NULL;
		}
	}
	else
	{
		if (!m_bSendVideoSignal)
		{
			if (m_bScreen)
			{
				if (!m_pVideoDecoder)
				{
					m_pVideoDecoder = new CH264Decoder(0, this);
					if (m_pVideoDecoder)
					{
						m_pVideoDecoder->SetVideoParam(m_nOutWidth, m_nOutHeigth);
					}
				}

				if (m_pVideoDecoder)
					m_pVideoDecoder->PutRecvData(pRecv);
			}
		}	
		else
		{
			if (pRecv)
			{
				if (pRecv->pData)
				{
					delete [] pRecv->pData;
					pRecv->pData = NULL;
				}

				delete pRecv;
				pRecv = NULL;
			}
		}
	}	
}

bool CManager::SendChatMessage(const char *pMessage)
{
	return m_pCmd->SendChatMessage(pMessage);
}

int	CManager::InitVideoCapture(void)
{
	return m_pVideoCapture->InitVideoCapture();
}

int CManager::UpdateVideoCapture(void)
{
	return m_pVideoCapture->UpdateVideoCaptureDevice();
}

int CManager::GetVideoCaptrueDevice(char *pData, int *pDataLen)
{
	vector<DeviceInfo> vecDeviceInfo;
	int nRet = -1;

	m_pVideoCapture->GetDeviceList(vecDeviceInfo);

	if (vecDeviceInfo.size())
	{
		string strJson;
		CJsonAnalysis::VideoCaptureDeviceList(strJson, vecDeviceInfo);

		if (*pDataLen >= strJson.length())
		{
			memset(pData, 0x00, *pDataLen);
			memcpy(pData, strJson.c_str(), strJson.length());

			nRet = *pDataLen = strJson.length();
		}
		else
		{
			*pDataLen = strJson.length();
			nRet = 0;
		}
	}

	return nRet;
}

int CManager::StartCaptrue(int nIndex, int nWidth, int nHeight, int nFrameRate)
{
	return m_pVideoCapture->StartDevCapture(nIndex, nWidth, nHeight, nFrameRate);
}

int CManager::StartCaptrueEx(const char *pUIDName, int nWidth, int nHeigth, int nFrameRate)
{
	return m_pVideoCapture->StartDevCaptureEx(pUIDName, nWidth, nHeigth, nFrameRate);
}

int CManager::StopCapture(int nIndex)
{
	return m_pVideoCapture->StopDevCapture(nIndex);
}

void CManager::ShowSetDialogBox(const char *pUIDName, const char *pTitle, void *pParentWindow, int nX, int nY)
{
	m_pVideoCapture->DisplaySetDialogBox(pUIDName, pTitle, pParentWindow, nX, nY);
}

void CManager::ShowSetDialogBoxEx(int nIndex, const char *pTitle, void *pParentWindow, int nX, int nY)
{
	m_pVideoCapture->DisplaySetDialogBoxEx(nIndex, pTitle, pParentWindow, nX, nY);
}

int CManager::SendDataByMediaChannel(int nCmd, const char *pData, int nDataLen)
{
	return m_pMedia->SendDataToServer(nCmd, pData, nDataLen);
}

void CManager::HandleRecvWBData(const char *pData, int nDataLen)
{
	m_pWb->HandleRecvWBData(pData, nDataLen);
}

void CManager::ThreadProcMain(void)
{
	while (!m_bExit)
	{
		while (m_lstRecvData.size())
		{
			LPRecvDataInfo pRecvData = NULL;

			{
				CAutoLock autoLock(&m_lockRecvData);
				pRecvData = (LPRecvDataInfo)m_lstRecvData.front();
				m_lstRecvData.pop_front();
			}

			if (pRecvData)
			{
				HandleRecvData(pRecvData);	

				if (pRecvData->pData)
				{
					delete [] pRecvData->pData;
					pRecvData->pData = NULL;
				}

				delete pRecvData;
				pRecvData = NULL;
			}
		}

		//TestAudio();

		my_sleep(2);
	}
}

void CManager::OnEncodeData(H264VideoParam *videoData)
{
	//OutputDebugString("CManager::OnEncodeData \n");
	m_pMedia->SendDataToServer(SCREEN_DATA, videoData->pBuf, videoData->nDataLen);	
}

void CManager::OnDecodeData(int nId, int nFrameRate, AVFrame *pAvFrame)
{
	unsigned char *pY = pAvFrame->data[0];
	unsigned char *pU = pAvFrame->data[1];
	unsigned char *pV = pAvFrame->data[2];

	if (!m_bInitRender)
		InitVideoRender(pAvFrame->width, pAvFrame->height);

	if (m_bInitRender)
	{
		SDL_LockYUVOverlay(m_pBmp);

		memcpy(m_pBmp->pixels[0], pY, pAvFrame->width * pAvFrame->height);
		memcpy(m_pBmp->pixels[2], pU, pAvFrame->width * pAvFrame->height/4);
		memcpy(m_pBmp->pixels[1], pV, pAvFrame->width * pAvFrame->height/4);

		SDL_UnlockYUVOverlay(m_pBmp);

		SDL_Rect rect;

		rect.x = 0;
		rect.y = 0;
		rect.w = m_nOutWidth;
		rect.h = m_nOutHeigth;

		SDL_DisplayYUVOverlay(m_pBmp, &rect);
	}

	if (m_bFirst)
	{
		my_sleep(10);
		NoticeMessage(show_screenBroadcastWindow, "show_screenBroadcastWindow");
		m_bFirst = false;		
		//m_pVideoCapture->SetDisplay(false);
	}
}

void CManager::OnCaptureData(int nId, const uint8_t * const pFrame[], int nWidth, int nHeight, uint64_t ulTimestamp)
{
	/*char szMsg[256] = {0};
	sprintf_s(szMsg, "CManager::OnCaptureData id:%d width:%d height:%d timestamp:%lu \n", nId, nWidth, nHeight, ulTimestamp);
	OutputDebugString(szMsg);*/

	CAutoLock autoLock(&m_lockSendVideoSignal);
	if (m_bSendVideoSignal)
	{
		if (!m_pVideoEncoder)
		{
			//OutputDebugString("CManager::OnCaptureData !m_pVideoEncoder\n");

			m_pVideoEncoder = new CVideoEncoder(this);

			EncoderParam encodeParam;
			encodeParam.nWidth = nWidth;
			encodeParam.nHeight = nHeight;

			encodeParam.nThreadNum = encodeParam.nWidth * encodeParam.nHeight < 1280 * 720 ? 1 : 2;

			m_pVideoEncoder->OpenEncoder(encodeParam);
		}

		if (m_pVideoEncoder)
			m_pVideoEncoder->PutYUVData(pFrame, nWidth, nHeight, GetTimeStamp());
	}	
}

void CManager::HandleRecvData(RecvDataInfo *pRecv)
{
	switch (pRecv->nCmd)
	{
	case CMDCHANNEL_BREAK:
		{
			m_bScreen = false;
			m_bSendVideoSignal = false;
			m_pVideoCapture->SetDisplay(true);

			if (m_pVideoEncoder)
			{
				delete m_pVideoEncoder;
				m_pVideoEncoder = NULL;
			}

			if (m_pVideoDecoder)
			{
				delete m_pVideoDecoder;
				m_pVideoDecoder = NULL;
			}

			NoticeMessage(cmdChannel_break, "cmdChannel_break");
		}		
		break;
	case CMDCHANNEL_CONNECT:
		NoticeMessage(cmdChannel_connect, "cmdChannel_connect");
		break;
	case MEDIACHANNEL_BREAK:
		NoticeMessage(mediaChannel_break, "mediaChannel_break");
		break;
	case MEDIACHANNEL_CONNECT:
		NoticeMessage(mediaChannel_connect, "mediaChannel_connect");
		break;
	case CMDCHANNEL_CONNECT_FAIL:
		NoticeMessage(cmdChannel_connect_fail, "cmdChannel_connect_fail");
		break;
	case MEDIACHANNEL_CONNECT_FAIL:
		NoticeMessage(mediaChannel_connect_fail, "mediaChannel_connect_fail");
		break;
	case CMD_S2T_EXTSIGNAL_CONTROL:
		HandleExtSignalControl(pRecv);
		break;
	case CMD_T2S_INVITESCREENCAST_REQ:
		HandleInviteScreenCast(pRecv);
		break;
	case CMD_T2S_STOPSCREENCAST:
		HandleStopScreen(pRecv);
		break;
	case CMD_S2T_MEETINGINFO:
		HandleMeetingInfo(pRecv);
		break;
	}
}

void CManager::NoticeMessage(int nType, const char *pMsg)
{
	if (m_pCallback)
		m_pCallback(nType, pMsg, m_pUser);
}

void CManager::HandleRecvFileEnd(void)
{
	m_pWb->CompleteFileReceivingTask();
}

bool CManager::InitVideoRender(int nWidth, int nHeight)
{
	/*RECT rc;
	GetClientRect((HWND)m_ulRemoteVideo, &rc);

	m_nOutWidth = rc.right - rc.left;
	m_nOutHeigth = rc.bottom - rc.top;*/

	char sdl[128] = {0};
	sprintf_s(sdl, "SDL_WINDOWID=0x%lx", m_ulRemoteVideo);
	SDL_putenv(sdl);

	SDL_Init(SDL_INIT_VIDEO);

	m_pScreen = SDL_SetVideoMode(m_nOutWidth, m_nOutHeigth, 32, SDL_SWSURFACE|SDL_ANYFORMAT);
	if (m_pScreen == NULL)
		return false;

	SDL_ShowCursor(0);

	m_pBmp = SDL_CreateYUVOverlay(nWidth, nHeight, SDL_YV12_OVERLAY, m_pScreen);

	m_bInitRender = true;

	return m_bInitRender;
}

void CManager::HandleInviteScreenCast(RecvDataInfo *pRecv)
{
	if (m_pCmd->OpenScreenBroadcast())
	{
		m_bSendVideoSignal = true;

		OutputDebugString("CManager::HandleInviteScreenCast m_bSendVideoSignal=true\n");
	}
}

void CManager::HandleMeetingInfo(RecvDataInfo *pRecv)
{
	MeetingInfo meetingInfo;

	m_bScreen = false;
	m_bSendVideoSignal = false;

	if (m_pVideoEncoder)
	{
		delete m_pVideoEncoder;
		m_pVideoEncoder = NULL;
	}

	if (m_pVideoDecoder)
	{
		delete m_pVideoDecoder;
		m_pVideoDecoder = NULL;
	}

	if (CJsonAnalysis::AnalysIssuedMeeting(pRecv->pData, &meetingInfo))
	{
		NoticeMessage(meetingInfo_notice, meetingInfo.strSlogan.c_str());
	}	
}

void CManager::HandleStopScreen(RecvDataInfo *pRecv)
{
	m_bSendVideoSignal = false;

	if (m_pVideoEncoder)
	{
		delete m_pVideoEncoder;
		m_pVideoEncoder = NULL;
	}

	OutputDebugString("CManager::HandleStopScreen m_bSendVideoSignal=false \n");
}

void CManager::HandleExtSignalControl(RecvDataInfo *pRecv)
{
	int nControlType(0);
	string strExtMsg;

	if (CJsonAnalysis::AnalysExtSignalControl(pRecv->pData, nControlType, strExtMsg))
	{
		switch (nControlType)
		{
		case 1:
			{
				CAutoLock autoLock(&m_lockSendVideoSignal);
				m_bSendVideoSignal = true;
			}
			break;
		case 2:
			{
				CAutoLock autoLock(&m_lockSendVideoSignal);
				m_bSendVideoSignal = false;

				if (m_pVideoEncoder)
				{
					delete m_pVideoEncoder;
					m_pVideoEncoder = NULL;
				}
			}
			break;
		case 3:
			{
				m_bScreen = true;
				m_bFirst = true;

				if (m_bSendVideoSignal)
				{
					m_pVideoCapture->SetDisplay(true);
					NoticeMessage(show_screenBroadcastWindow, "show_screenBroadcastWindow");
				}
				else
				{
					m_pVideoCapture->SetDisplay(false);
				}
				
				//NoticeMessage(show_screenBroadcastWindow, "show_screenBroadcastWindow");
				OutputDebugString("CManager::HandleExtSignalControl SetDisplay(false) \n");
			}
			break;
		case 4:
			{
				m_bScreen = false;
				m_pVideoCapture->SetDisplay(true);	

				if (m_pVideoDecoder)
				{
					delete m_pVideoDecoder;
					m_pVideoDecoder = NULL;
				}

				/*if (m_bSendVideoSignal)
				{
					m_bSendVideoSignal = false;

					if (m_pVideoEncoder)
					{
						delete m_pVideoEncoder;
						m_pVideoEncoder = NULL;
					}
				}*/
				OutputDebugString("CManager::HandleExtSignalControl SetDisplay(true) \n");
			}
			NoticeMessage(hide_screenBroadcastWindow, "hide_screenBroadcastWindow");
			break;
		case 5:
			NoticeMessage(show_whiteBoradWindow, "show_whiteBoradWindow");
			break;
		case 6:
			NoticeMessage(hide_whiteBoradWindow, "hide_whiteBoradWindow");
			break;
		case 7:
			NoticeMessage(show_meetingSloganWindow, strExtMsg.c_str());
			break;
		case 8:
			NoticeMessage(hide_meetingSloganWindow, "hide_meetingSloganWindow");
			break;
		case 9:
			NoticeMessage(show_meetingVoteWindow, strExtMsg.c_str());
			break;
		case 10:
			NoticeMessage(hide_meetingVoteWindow, "hide_meetingVoteWindow");
			break;
		case 11:
			{
				m_bScreen = false;
				m_pVideoCapture->SetDisplay(true);	

				if (m_pVideoDecoder)
				{
					delete m_pVideoDecoder;
					m_pVideoDecoder = NULL;
				}

				NoticeMessage(meetingEnd_notice, "meetingEnd_notice");
			}			
			break;
		default:
			break;
		}
	
	}
}
